home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / games / IndiZone / oort / multicast.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  5.7 KB  |  250 lines

  1. /*
  2.  * Copyright (C) 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. /***************************************************************************
  18.  *
  19.  * @(#) - Oort - Multicast Socket Routines.
  20.  *
  21.  * $Id: multicast.c,v 1.2 1994/01/28 00:19:52 mtj Exp $
  22.  *
  23.  *                    Chris Fouts - Silicon Graphics, Inc.
  24.  *                    October, 1991
  25.  **************************************************************************/
  26. #include <stdlib.h>
  27. #include <bstring.h>
  28. #include <getopt.h>
  29. #include <string.h>
  30. #include <stdio.h>
  31. #include <time.h>
  32. #include <ctype.h>
  33. #include <unistd.h>
  34. #include <sys/types.h>
  35. #ifndef    sgi
  36. #define    sgi
  37. #define    UN_SGI
  38. #endif /* sgi */
  39. #include <sys/socket.h>
  40. #include <net/if.h>
  41. #include <netinet/in.h>
  42. #include <net/soioctl.h>
  43. #include <arpa/inet.h>
  44. #ifdef UN_SGI
  45. #undef    sgi
  46. #endif /* UN_SGI */
  47. #include <fcntl.h>
  48. #include "multicast.h"
  49.  
  50.  
  51. int ioctl( int fildes, int request, ... ) ;
  52.  
  53. /* BEGIN PROTOTYPES -S multicast.c */
  54. static int  checkInterface( const char *interface, int fd, char mode,
  55.                 struct in_addr *ifaddr ) ;
  56. /* END PROTOTYPES -S multicast.c */
  57.  
  58.  
  59. /*------------------------------------------------------------------------------
  60.  * Open up a multicast socket for reading or writing.
  61.  *----------------------------------------------------------------------------*/
  62. int
  63. openMulticastSocket(
  64.     struct sockaddr_in    *addr,
  65.     u_short            port,
  66.     u_char            ttl,
  67.     u_char            loop,
  68.     const char        *group,
  69.     const char        *interface,
  70.     const char        *mode_str
  71.     )
  72. {
  73.     int            fd ;
  74.     int            st ;
  75.     int            on;
  76.     char            mode = tolower( *mode_str ) ;
  77.     struct in_addr        ifaddr;
  78.     struct in_addr        grpaddr;
  79.     struct ip_mreq        mreq;
  80.  
  81.     grpaddr.s_addr = inet_addr( group ) ;
  82.     if( !IN_MULTICAST( grpaddr.s_addr ) )
  83.     {
  84.         fprintf( stderr, "Invalid multicast group address: %s\n",
  85.             group ) ;
  86.         return( -1 ) ;
  87.     }
  88.  
  89.     if( strlen( mode_str ) != 1 || ( mode != 'r' && mode != 'w' ) )
  90.     {
  91.         fprintf( stderr, "openMulticastSocket: improper mode `%s'\n",
  92.                     mode_str ) ;
  93.         return( -1 ) ;
  94.     }
  95.  
  96.     fd = socket( AF_INET, SOCK_DGRAM, 0 ) ;
  97.     if( fd < 0 )
  98.     {
  99.         perror( "socket" ) ;
  100.         return( fd ) ;
  101.     }
  102.  
  103.     bzero( addr, sizeof( *addr ) ) ;
  104.     addr->sin_family = AF_INET ;
  105.     addr->sin_addr.s_addr = INADDR_ANY ;
  106.     addr->sin_port = htons( port ) ;
  107.  
  108.     ifaddr.s_addr = INADDR_ANY;
  109.  
  110.     if( interface != NULL &&
  111.         ( st = checkInterface( interface, fd, mode, &ifaddr ) ) < 0 )
  112.     {
  113.         close( fd ) ;
  114.         return( st ) ;
  115.     }
  116.  
  117.     switch( mode )
  118.     {
  119.  
  120.         case 'w' :
  121.             if( setsockopt( fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl,
  122.                             sizeof(ttl) ) )
  123.             {
  124.                 close( fd ) ;
  125.                 perror( "setsockopt TTL" ) ;
  126.                 return( -1 ) ;
  127.             }
  128.  
  129.             if( setsockopt( fd, IPPROTO_IP, IP_MULTICAST_LOOP,
  130.                         &loop, sizeof(loop) ) )
  131.             {
  132.                 close( fd ) ;
  133.                 perror( "setsockopt LOOP" ) ;
  134.                 return( -1 ) ;
  135.             }
  136.  
  137.             addr->sin_addr = grpaddr;
  138.             break ;
  139.  
  140.         case 'r' :
  141.             /* 
  142.              * Allow multiple instances of this program to listen
  143.              * on the same port on the same host. By default only
  144.              * 1 program can bind to the port on a host.
  145.              */
  146.             on = 1;
  147.             if( setsockopt( fd, SOL_SOCKET, SO_REUSEPORT, &on,
  148.                             sizeof(on) ) < 0 )
  149.             {
  150.                 close( fd ) ;
  151.                 perror( "setsockopt REUSEPORT" ) ;
  152.                 return( -1 ) ;
  153.             }
  154.  
  155.             if( bind( fd, addr, sizeof(*addr) ) < 0 )
  156.             {
  157.                 close( fd ) ;
  158.                 perror( "bind" ) ;
  159.                 return( -1 ) ;
  160.             }
  161.  
  162.             mreq.imr_multiaddr = grpaddr;
  163.             mreq.imr_interface = ifaddr;
  164.             if( setsockopt( fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
  165.                         &mreq, sizeof(mreq) ) < 0 )
  166.             {
  167.                 close( fd ) ;
  168.                 perror( "setsockopt ADD" ) ;
  169.                 return( -1 ) ;
  170.             }
  171.             break ;
  172.  
  173.     }
  174.  
  175.     return( fd ) ;
  176. }
  177.  
  178.  
  179.  
  180. /*------------------------------------------------------------------------------
  181.  * Make sure the specified interface exists and is capable of doing
  182.  * multicasting.
  183.  *----------------------------------------------------------------------------*/
  184. static int
  185. checkInterface(
  186.     const char    *interface,
  187.     int        fd,
  188.     char        mode,
  189.     struct in_addr    *ifaddr
  190.     )
  191. {
  192.     int        i ;
  193.     struct ifconf    ifc ;
  194.     struct ifreq    *ifr ;
  195.     char        buf[BUFSIZ] ;
  196.  
  197.     ifc.ifc_len = sizeof( buf ) ;
  198.     ifc.ifc_buf = buf ;
  199.     if( ioctl( fd, SIOCGIFCONF, (char *) &ifc ) < 0 )
  200.     {
  201.         perror( "ioctl SIOCGIFCONF" ) ;
  202.         return( -1 ) ;
  203.     }
  204.  
  205.     ifr = ifc.ifc_req;
  206.     for( i = ifc.ifc_len/sizeof(*ifr) ; --i >= 0 ; ifr++ )
  207.     {
  208.         if( ifr->ifr_addr.sa_family != AF_INET )
  209.             continue ;
  210.  
  211.         if( strncmp( ifr->ifr_name, interface, strlen( ifr->ifr_name ) )
  212.             == 0 )
  213.         {
  214.             /* Obtain the interface's assigned network address */
  215.             *ifaddr = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr ;
  216.  
  217.             if( ioctl( fd, SIOCGIFFLAGS, (char *) ifr ) < 0 )
  218.             {
  219.                 perror( "ioctl SIOCGIFFLAGS" ) ;
  220.                 return( -1 ) ;
  221.             }
  222.             if( !( ifr->ifr_flags & IFF_MULTICAST ) )
  223.             {
  224.                 fprintf( stderr, "%s: interface doesn't support"
  225.                     " multicasting\n", interface ) ;
  226.                 return( -1 ) ;
  227.             }
  228.  
  229.             /* Specify the interface to use when sending packets */
  230.             if( mode == 'w' &&
  231.                 setsockopt( fd, IPPROTO_IP, IP_MULTICAST_IF,
  232.                     ifaddr, sizeof(*ifaddr) ) < 0 )
  233.             {
  234.                 perror( "setsockopt MULTICAST" ) ;
  235.                 return( -1 ) ;
  236.             }
  237.             break;
  238.         }
  239.     }
  240.  
  241.     if( ifaddr->s_addr == INADDR_ANY )
  242.     {
  243.         fprintf( stderr, "%s: invalid or unknown interface\n",
  244.             interface ) ;
  245.         return( -1 ) ;
  246.     }
  247.  
  248.     return( 0 ) ;
  249. }
  250.